#include "stm32f0xx_ll_tim.h"
#include "stm32f0xx_ll_bus.h"
#include "drv_timer.h"
#include "drv_timer_cfg.h"

/** --------------- 定时器的内部配置 --------------- */
/// 定时器时钟分频
#define _DRV_TIMER_PRESCALER        (24000-1)       ///< 48000 的一半，即分配后一次count为0.5ms

typedef void (*_TDrv_Timer_ClockEnable)(uint32_t);
typedef void (*_TDrv_Timer_ClockDisable)(uint32_t);

/// 每个timerx的对象指针
static void* g_drv_timer[DRV_TIMER_COUNT] = {NULL};

/// 定时器bus定义
const static UInt32 g_drv_timer_bus[] = 
{
    LL_APB1_GRP2_PERIPH_TIM1, 
    LL_APB1_GRP1_PERIPH_TIM3, 
    LL_APB1_GRP1_PERIPH_TIM6, 
    LL_APB1_GRP1_PERIPH_TIM14,
    LL_APB1_GRP2_PERIPH_TIM15, 
    LL_APB1_GRP2_PERIPH_TIM16, 
    LL_APB1_GRP2_PERIPH_TIM17
};

/// 总线使能函数定义
const static _TDrv_Timer_ClockEnable g_drv_timer_clock_enable[] = 
{
    LL_APB1_GRP1_EnableClock, 
    LL_APB1_GRP2_EnableClock
};

/// 总线失能函数定义
const static _TDrv_Timer_ClockDisable g_drv_timer_clock_disable[] = 
{
    LL_APB1_GRP1_DisableClock, 
    LL_APB1_GRP2_DisableClock
};

/// 中断号定义
const static IRQn_Type g_drv_timer_irqn[] = 
{
    TIM1_CC_IRQn, 
    TIM3_IRQn, 
    TIM6_IRQn, 
    TIM14_IRQn, 
    TIM15_IRQn, 
    TIM16_IRQn, 
    TIM17_IRQn
};

typedef struct
{
    /// 用序号可以节省一些空间
    UInt32 timerx;                  ///< 定时器定义
    UInt8 bus_index;                ///< 在哪条总线序号
    UInt8 clock_enable_index;       ///< 总线使能函数序号
    UInt8 clock_disable_index;      ///< 总线失能函数序号
    UInt8 irqn_index;               ///< 中断号序号
}TDrv_Timer_Diff;

/// 每个定时器的内部不同配置
const static TDrv_Timer_Diff g_drv_timer_diff[DRV_TIMER_COUNT] = 
{
    {
        .timerx                 = kDrv_Timer0,
        .bus_index              = 0,
        .clock_enable_index     = 1,
        .clock_disable_index    = 1,
        .irqn_index             = 0,
    },
    {
        .timerx                 = kDrv_Timer1,
        .bus_index              = 1,
        .clock_enable_index     = 0,
        .clock_disable_index    = 0,
        .irqn_index             = 1,
    },
    {
        .timerx                 = kDrv_Timer2,
        .bus_index              = 2,
        .clock_enable_index     = 0,
        .clock_disable_index    = 0,
        .irqn_index             = 2,
    },
    {
        .timerx                 = kDrv_Timer3,
        .bus_index              = 3,
        .clock_enable_index     = 0,
        .clock_disable_index    = 0,
        .irqn_index             = 3,
    },
    {
        .timerx                 = kDrv_Timer4,
        .bus_index              = 4,
        .clock_enable_index     = 1,
        .clock_disable_index    = 1,
        .irqn_index             = 4,
    },
    {
        .timerx                 = kDrv_Timer5,
        .bus_index              = 5,
        .clock_enable_index     = 1,
        .clock_disable_index    = 1,
        .irqn_index             = 5,
    },
    {
        .timerx                 = kDrv_Timer6,
        .bus_index              = 6,
        .clock_enable_index     = 1,
        .clock_disable_index    = 1,
        .irqn_index             = 6,
    },
};
/** -------------- END定时器的内部配置 ------------- */

/// 获得timerx宏定义的序号
/// -1 表示不存在timerx的序号
static Int8 _Drv_Timer_Index(UInt32 timerx)
{
    Int8 i = sizeof(g_drv_timer_diff) / sizeof(g_drv_timer_diff[0]);
    const TDrv_Timer_Diff* diff = g_drv_timer_diff;

    for (i = i - 1; i >= 0; i--)
        if (diff[i].timerx == timerx)
            break;

    return i;
}

/** --------------------- 中断服务函数 ------------------------ */
/// 定时器通用中断处理
static void _Drv_Timer_IqrCommon(void* obj)
{
    TDrv_Timer* timer = (TDrv_Timer*)obj;
    TDrv_Timer_Cfg* cfg = (TDrv_Timer_Cfg*)timer->cfg;
    LL_TIM_ClearFlag_UPDATE((TIM_TypeDef *)cfg->timx);  ///< 清除中断标志
    if (timer != NULL && timer->event.event != NULL)
    {
        timer->event.event(timer->event.user_param);
    }
}

/// 定时器1
void TIM1_BRK_UP_TRG_COM_IRQHandler(void)
{
    _Drv_Timer_IqrCommon(g_drv_timer[0]);   ///< 这里为了效率直接取'0'这一具体值
}

/// 定时器3
void TIM3_IRQHandler(void)
{
    _Drv_Timer_IqrCommon(g_drv_timer[1]);   ///< 这里为了效率直接取'1'这一具体值
}

/// 定时器6
void TIM6_IRQHandler(void)
{
    _Drv_Timer_IqrCommon(g_drv_timer[2]);   ///< 这里为了效率直接取'2'这一具体值
}

/// 定时器14
void TIM14_IRQHandler(void)
{
    _Drv_Timer_IqrCommon(g_drv_timer[3]);   ///< 这里为了效率直接取'3'这一具体值
}

/// 定时器15
void TIM15_IRQHandler(void)
{
    _Drv_Timer_IqrCommon(g_drv_timer[4]);   ///< 这里为了效率直接取'4'这一具体值
}

/// 定时器16
void TIM16_IRQHandler(void)
{
    _Drv_Timer_IqrCommon(g_drv_timer[5]);   ///< 这里为了效率直接取'5'这一具体值
}

/// 定时器17
void TIM17_IRQHandler(void)
{
    _Drv_Timer_IqrCommon(g_drv_timer[6]);   ///< 这里为了效率直接取'6'这一具体值
}
/** --------------------- END中断服务函数 ------------------------ */

Int32 TDrv_Timer_Init(TDrv_Timer* timer, const void* cfg)
{
    Int32 result = kDrv_Error_Param;

    if (timer != NULL && cfg != NULL)
    {
        timer->cfg = cfg;
        timer->event.event = NULL;
        timer->event.user_param = NULL;
        timer->update_ms = 0;
        timer->is_open = False;

        TDrv_Timer_Cfg* timer_cfg = (TDrv_Timer_Cfg*)timer->cfg;
        Int8 index = _Drv_Timer_Index(timer_cfg->timx);

        /// 如果index<0表示cfg中的定时器是不存在的
        if (index >= 0)
        {
            g_drv_timer[index] = timer;     ///< 将对象保存到数组

            const TDrv_Timer_Diff* diff = &g_drv_timer_diff[index];
            
            /* Peripheral clock enable */
            g_drv_timer_clock_enable[diff->clock_enable_index](g_drv_timer_bus[diff->bus_index]);

            NVIC_SetPriority(g_drv_timer_irqn[diff->irqn_index], 0);
            NVIC_EnableIRQ(g_drv_timer_irqn[diff->irqn_index]);

            LL_TIM_InitTypeDef TIM_InitStruct = {0};
            TIM_InitStruct.Prescaler = _DRV_TIMER_PRESCALER;
            TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;     ///< 每个定时器固定向上计数
            TIM_InitStruct.Autoreload = timer->update_ms;
            LL_TIM_Init((TIM_TypeDef *)timer_cfg->timx, &TIM_InitStruct);
            LL_TIM_DisableARRPreload((TIM_TypeDef *)timer_cfg->timx);

            /* Peripheral clock disable */
            // g_drv_timer_clock_disable[diff->clock_disable_index](g_drv_timer_bus[diff->bus_index]);

            result = kDrv_Error_Success;
        }
        else
            result = kDrv_Error_CfgError;
    }
    else
        result = kDrv_Error_Param;

    return result;
}

Int32 TDrv_Timer_DeInit(TDrv_Timer* timer)
{
    Int32 result;

    if (timer->is_open)
        result = kDrv_Error_NotClose;
    else
    {
        TDrv_Timer_Cfg* timer_cfg = (TDrv_Timer_Cfg*)timer->cfg;

        if (timer_cfg == NULL)
            result = kDrv_Error_CfgError;
        else
        {
            Int8 index = _Drv_Timer_Index(timer_cfg->timx);
            const TDrv_Timer_Diff* diff = &g_drv_timer_diff[index];

            LL_TIM_DeInit((TIM_TypeDef *)timer_cfg->timx);
            
            NVIC_DisableIRQ(g_drv_timer_irqn[diff->irqn_index]);
            
            /* Peripheral clock disable */
            g_drv_timer_clock_disable[diff->clock_disable_index](g_drv_timer_bus[diff->bus_index]);

            g_drv_timer[index] = NULL;     ///< 不保存对象指针

            timer->cfg = NULL;
            timer->event.event = NULL;
            timer->event.user_param = NULL;
            timer->update_ms = 0;
            timer->is_open = False;

            result = kDrv_Error_Success;
        }
    }
    
    return result;
}

void TDrv_Timer_SetUpdateMs(TDrv_Timer* timer, UInt16 ms)
{
    timer->update_ms = ms;
}

Int32 TDrv_Timer_Open(TDrv_Timer* timer)
{
    Int32 result;

    if (timer->is_open)
        result = kDrv_Error_HasOpened;
    else
    {
        TDrv_Timer_Cfg* cfg = (TDrv_Timer_Cfg*)timer->cfg;
        Int8 index = _Drv_Timer_Index(cfg->timx);
//        const TDrv_Timer_Diff* diff = &g_drv_timer_diff[index];
        
        /* Peripheral clock enable */
        // g_drv_timer_clock_enable[diff->clock_enable_index](g_drv_timer_bus[diff->bus_index]);

        /* Set the Autoreload value */
        LL_TIM_SetAutoReload((TIM_TypeDef *)cfg->timx, timer->update_ms);

        LL_TIM_ClearFlag_UPDATE((TIM_TypeDef *)cfg->timx);  ///< 清除中断标志, 在开启中断前加一句，不加会导致开启后马上进入中断
        LL_TIM_EnableIT_UPDATE((TIM_TypeDef *)cfg->timx);
        LL_TIM_EnableCounter((TIM_TypeDef *)cfg->timx);

        timer->is_open = True;
        result = kDrv_Error_Success;
    }

    return result;
}

Int32 TDrv_Timer_Close(TDrv_Timer* timer)
{
    Int32 result;

    if (!timer->is_open)
        result = kDrv_Error_HasClosed;
    else
    {
        timer->is_open = False;
        
        TDrv_Timer_Cfg* cfg = (TDrv_Timer_Cfg*)timer->cfg;
        Int8 index = _Drv_Timer_Index(cfg->timx);
//        const TDrv_Timer_Diff* diff = &g_drv_timer_diff[index];

        LL_TIM_DisableCounter((TIM_TypeDef *)cfg->timx);
        LL_TIM_DisableIT_UPDATE((TIM_TypeDef *)cfg->timx);

        /* Peripheral clock disable */
        // g_drv_timer_clock_disable[diff->clock_disable_index](g_drv_timer_bus[diff->bus_index]);

        result = kDrv_Error_Success;
    }

    return result;
}

Int32 TDrv_Timer_IsOpen(TDrv_Timer* timer)
{
    return timer->is_open;
}

Int32 TDrv_Timer_SetUpdateEvent(TDrv_Timer* timer, TDrv_Timer_OnUpdateEvent event_obj)
{
    Int32 result;

    if (timer->is_open)
        result = kDrv_Error_NotClose;
    else 
    {
        timer->event.event = event_obj.event;
        timer->event.user_param = event_obj.user_param;
        __DMB();
    }

    return result;
}
